use strict;

package Graphics::PlanarVector::Vector;
use Graphics::PlanarVector::Util;

use Carp;
use Exporter 'import';
our @EXPORT_OK = qw/vector len2 dist2 veq vdiv/;

use Graphics::PlanarVector::Transform qw/scale rotate translate/;

use overload (
	'""'	=> sub {
		my $v = shift;
		join(',', map { sprintf('%.3f', $_) + 0 } @$v)
		#"@$v";
	},
	'bool'	=> sub { 1 },

	'+'	=>sub {
		vector($_[0][0] + $_[1][0], $_[0][1] + $_[1][1])
	},

	'+='	=> sub {
		$_[0][0] += $_[1][0];
		$_[0][1] += $_[1][1];
		$_[0]
	},

	'neg'	=> sub {
		vector(-$_[0][0], -$_[0][1]);
	},

	'-'	=> sub {
		vector($_[0][0] - $_[1][0], $_[0][1] - $_[1][1]);
	},

	'-='	=> sub {
		$_[0][0] -= $_[1][0];
		$_[0][1] -= $_[1][1];
		$_[0]
	},

	'*'	=> sub {
		vector($_[0][0] * $_[1], $_[0][1] * $_[1])
	},

	'*='	=> sub {
		my ($v, $r, $swap) = @_;
		$swap || ref($r)	and croak "Bad arguments";

		$v->[0] *= $r;
		$v->[1] *= $r;
		$v
	},

	'/'	=> sub {
		my ($v, $r) = @_;
		vector($v->[0] / $r, $v->[1] / $r)
	},

	'/='	=> sub {
		my ($v, $r) = @_;
		$v->[0] /= $r;
		$v->[1] /= $r;
		$v
	},

	'&'	=> sub {
		$_[0][0] * $_[1][0] + $_[0][1] * $_[1][1];
	},

	'^'	=> sub {
		$_[0][0] * $_[1][1] - $_[0][1] * $_[1][0];
	},

	'='	=> sub { bless [@{shift()}] },
);

sub vector {
	bless [@_];
}

sub dup {
	bless [@{shift()}]
}

sub len2 {
	$_[0][0] * $_[0][0] + $_[0][1] * $_[0][1]
}

sub dist2 {
	len2(shift() - shift())
}

sub normalize {
	my $v = shift;
	my $len = len2($v) or return vector(0,0);
	$v / sqrt($len)
}

sub transform {
	my ($v, $m) = @_;
	bless [	$m->[0] * $v->[0] + $m->[2] * $v->[1] + $m->[4],
		$m->[1] * $v->[0] + $m->[3] * $v->[1] + $m->[5] ];
		
}

sub angle {
	atan2 $_[0][1], $_[0][0]
}

sub veq {
	abs($_[0][0] - $_[1][0]) < 1e-5 and
	abs($_[0][1] - $_[1][1]) < 1e-5;
}

sub vdiv {
	my ($a, $b) = @_;
	my $x = (abs($a->normalize^$b->normalize) > 1e-8);
	my $b2 = $b&$b	or return;
	return $x ? undef : ($a & $b)/$b2
}

1;
__END__

=head1 NAME

Graphics::PlanarVector::Vector -- Two dimension vector object.

=head1 SYNOPSIS

    use Graphics::PlanarVector::Vector 'vector';

    $p1 = vector(0, 1);
    $p2 = $p1 * 3 - vector(2.1,-3.3);
    print $p1 + $p2->scale(90);

=over 4

=item B<vector>($x, $y)

Importable function. Produces a 2-D vector object.

=item Operators 'B<+>', binary 'B<->', 'B<*>', 'B</>', uinary 'B<->' (negation)

The '+' and '-' operators work with two vectors; '*' and '/' work between a
vector and a number.  They do what you have probably expected.

=item Operators 'B<&>' and 'B<^>'

Both are binary vector-vector operators.  'B<&>' is dot product; 'B<^>' is
cross product.  Both produce a scalar.

=item B<scale>(), B<translate>(), B<rotate>() and B<transform>()

Transformation functions.  See L<Graphics::PlanarVector::Transform>.  Each
produces a new vector.

